
package com.hlkj.pay.service.order.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.hlkj.framework.common.pojo.LocalContext;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.hlkj.pay.dto.LocalMerchantRequest;
import com.hlkj.pay.dto.order.OrderSubsidyDto;
import com.hlkj.pay.dto.order.PayOrderSubsidyDto;
import com.hlkj.pay.dto.order.PayOrderSubsidyQueryDto;
import com.hlkj.pay.dto.order.RefundOrderSubsidyDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.infrastructure.mapper.order.OrderSubsidyDetailMapper;
import com.hlkj.pay.infrastructure.mapper.order.OrderSubsidyMapper;
import com.hlkj.pay.infrastructure.model.order.OrderFundDetailDO;
import com.hlkj.pay.infrastructure.model.order.OrderSubsidyDO;
import com.hlkj.pay.infrastructure.model.order.OrderSubsidyDetailDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.service.CommonSnFilterService;
import com.hlkj.pay.service.order.IPayOrdeSubsidyService;
import com.hlkj.pay.vo.order.req.SubsidyOrderParamReq;
import com.hlkj.pay.vo.order.req.SubsidyRefundOrderParamReq;

import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2025/01/02 10:32
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class PayOrderSubsidyServiceImpl extends CommonSnFilterService implements IPayOrdeSubsidyService {

    private final OrderSubsidyMapper orderSubsidyMapper;

    private final OrderSubsidyDetailMapper orderSubsidyDetailMapper;

    @Override
    public OrderSubsidyDto addSubsidyInfo(SubsidyOrderParamReq subsidyOrderParamReq, List<PayOrderSubsidyDto> payOrderSubsidyDtos, PayOrderDO payOrderDO) {
        // 补贴详情组装
        List<OrderSubsidyDetailDO> subsidyDetailDOList = new ArrayList<>();
        payOrderSubsidyDtos.stream().forEach(payOrderSubsidyDto -> {
            OrderSubsidyDetailDO orderSubsidyDetailDO = new OrderSubsidyDetailDO();
            orderSubsidyDetailDO.setAccountNo(payOrderSubsidyDto.getAccountNo());
            orderSubsidyDetailDO.setSuccessTime(payOrderSubsidyDto.getSuccessTime());
            orderSubsidyDetailDO.setAmount(new BigDecimal(payOrderSubsidyDto.getAmount()).setScale(2,BigDecimal.ROUND_HALF_UP));
            orderSubsidyDetailDO.setSubsidyStatus(payOrderSubsidyDto.getStatus().getCode());
            orderSubsidyDetailDO.setBatchNo(payOrderSubsidyDto.getBatchNo());
            orderSubsidyDetailDO.setBatchNoDetail(payOrderSubsidyDto.getBatchNoDetail());
            orderSubsidyDetailDO.setFailReason(payOrderSubsidyDto.getFailReason());
            subsidyDetailDOList.add(orderSubsidyDetailDO);
        });
        OrderSubsidyDO orderSubsidyDO = new OrderSubsidyDO();
        orderSubsidyDO.setPayOrderNo(payOrderDO.getPayOrderNo());
        orderSubsidyDO.setSn(payOrderDO.getOrderSn());
        if (subsidyOrderParamReq != null) {
            orderSubsidyDO.setNotifyUrl(subsidyOrderParamReq.getNotifyUrl());
            orderSubsidyDO.setSubsidyStatus(PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.PROCESSING.getCode());
        }
        else {
            orderSubsidyDO.setSubsidyStatus(PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.INIT.getCode());
        }
        orderSubsidyDO.setMchOrderNo(payOrderDO.getMchOrderNo());
        orderSubsidyDO.setSubsidyProcessType(payOrderDO.getMarketProcessType());
        orderSubsidyDO.setPayType(CommonEnum.YES_NO_TYPE.NO.getCode());
        orderSubsidyDO.setSystemProcessType( PayOrderEnums.SYSTEM_PROCESS_TYPE.MERCHANT.getCode());
        LocalMerchantRequest localMerchantRequest = (LocalMerchantRequest) LocalContext.get();
        orderSubsidyDO.setAppId(localMerchantRequest.getAppId());
        orderSubsidyDO.setSignType(localMerchantRequest.getSignType());
        orderSubsidyDO.setBatchNo(subsidyDetailDOList.get(0).getBatchNo());
        orderSubsidyMapper.insert(orderSubsidyDO);
        orderSubsidyDetailMapper.insertBatch(subsidyDetailDOList);
        OrderSubsidyDto orderSubsidyDto = new OrderSubsidyDto();
        orderSubsidyDto.setOrderSubsidyDO(orderSubsidyDO);
        orderSubsidyDto.setOrderSubsidyDetailList(subsidyDetailDOList);
        return orderSubsidyDto;
    }

    @Override
    public OrderSubsidyDto addSubsidyRefundInfo(SubsidyRefundOrderParamReq subsidyOrderParamReq, List<RefundOrderSubsidyDto> refundOrderSubsidyList, PayOrderDO payOrderDO,String requestId) {
        // 补贴详情组装
        List<OrderSubsidyDetailDO> subsidyDetailDOList = new ArrayList<>();
        refundOrderSubsidyList.stream().forEach(payOrderSubsidyDto -> {
            OrderSubsidyDetailDO orderSubsidyDetailDO = new OrderSubsidyDetailDO();
            orderSubsidyDetailDO.setAccountNo(payOrderSubsidyDto.getAccountNo());
            orderSubsidyDetailDO.setSuccessTime(payOrderSubsidyDto.getSuccessTime());
            orderSubsidyDetailDO.setAmount(new BigDecimal(payOrderSubsidyDto.getAmount()).setScale(2,BigDecimal.ROUND_HALF_UP));
            orderSubsidyDetailDO.setSubsidyStatus(payOrderSubsidyDto.getStatus().getCode());
            orderSubsidyDetailDO.setBatchNo(payOrderSubsidyDto.getBatchNo());
            orderSubsidyDetailDO.setOrderNo(payOrderSubsidyDto.getSubsidyOrderNo());
            orderSubsidyDetailDO.setOutOrderNo(payOrderSubsidyDto.getSubsidyBackOrderNo());
            orderSubsidyDetailDO.setBatchNoDetail(payOrderSubsidyDto.getBatchNoDetail());
            orderSubsidyDetailDO.setFailReason(payOrderSubsidyDto.getFailReason());
            subsidyDetailDOList.add(orderSubsidyDetailDO);
        });
        OrderSubsidyDO orderSubsidyDO = new OrderSubsidyDO();
        orderSubsidyDO.setPayOrderNo(payOrderDO.getPayOrderNo());
        orderSubsidyDO.setSn(payOrderDO.getOrderSn());
        if (subsidyOrderParamReq != null) {
            orderSubsidyDO.setNotifyUrl(subsidyOrderParamReq.getNotifyUrl());
            orderSubsidyDO.setSubsidyStatus(PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.PROCESSING.getCode());
        }
        else {
            orderSubsidyDO.setSubsidyStatus(PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.INIT.getCode());
        }
        orderSubsidyDO.setSubsidyProcessType(payOrderDO.getMarketProcessType());
        orderSubsidyDO.setSubsidyStatus(payOrderDO.getMarketProcessType());
        orderSubsidyDO.setPayType(CommonEnum.YES_NO_TYPE.YES.getCode());
        orderSubsidyDO.setSystemProcessType( PayOrderEnums.SYSTEM_PROCESS_TYPE.MERCHANT.getCode());
        LocalMerchantRequest localMerchantRequest = (LocalMerchantRequest) LocalContext.get();
        orderSubsidyDO.setAppId(localMerchantRequest.getAppId());
        orderSubsidyDO.setSignType(localMerchantRequest.getSignType());
        orderSubsidyDO.setBatchNo(subsidyDetailDOList.get(0).getBatchNo());
        orderSubsidyDO.setSubsidyRequestId(requestId);
        orderSubsidyMapper.insert(orderSubsidyDO);
        orderSubsidyDetailMapper.insertBatch(subsidyDetailDOList);
        OrderSubsidyDto orderSubsidyDto = new OrderSubsidyDto();
        orderSubsidyDto.setOrderSubsidyDO(orderSubsidyDO);
        orderSubsidyDto.setOrderSubsidyDetailList(subsidyDetailDOList);
        return orderSubsidyDto;

    }

    @Override
    public void updateAcctInfoCallBack(PayOrderDO orderDb, List<OrderFundDetailDO> orderFunds) {

    }

    @Override
    public List<OrderSubsidyDetailDO>  queryPaySubsidyInfo(String payOrderNo) {
        List<OrderSubsidyDO> orderSubsidyList = orderSubsidyMapper.selectList(OrderSubsidyDO::getPayOrderNo, payOrderNo);
        if (CollectionUtils.isEmpty(orderSubsidyList)) {
            return Collections.emptyList();
        }
        List<String> batchNos = orderSubsidyList.stream().map(orderSubsidyDO -> orderSubsidyDO.getBatchNo()).collect(Collectors.toList());
        PayOrderSubsidyQueryDto payOrderSubsidyQueryDto = new PayOrderSubsidyQueryDto();
        payOrderSubsidyQueryDto.setBatchNos(batchNos);
        return orderSubsidyDetailMapper.selectList(buildDetailQueryWrapper(payOrderSubsidyQueryDto));
    }

    @Override
    public OrderSubsidyDO queryOrderSubsidyInfo(String batchNo, String mchOrderNo) {
        PayOrderSubsidyQueryDto payOrderSubsidyQueryDto = new PayOrderSubsidyQueryDto();
        payOrderSubsidyQueryDto.setBatchNo(batchNo);
        payOrderSubsidyQueryDto.setMchOrderNo(mchOrderNo);
        return orderSubsidyMapper.selectOne(buildQueryWrapper(payOrderSubsidyQueryDto));
    }

    @Override
    public OrderSubsidyDO queryRefundSubsidyInfo(String batchNo, String mchAcctRefundOrderNo) {
        PayOrderSubsidyQueryDto payOrderSubsidyQueryDto = new PayOrderSubsidyQueryDto();
        payOrderSubsidyQueryDto.setBatchNo(batchNo);
        payOrderSubsidyQueryDto.setMchRefundOrderNo(mchAcctRefundOrderNo);
        return orderSubsidyMapper.selectOne(buildQueryWrapper(payOrderSubsidyQueryDto));
    }


    @Override
    public OrderSubsidyDto updateSubsidy(List<OrderSubsidyDetailDO> orderSubsidyDetailDOList, String batchNo) {
        orderSubsidyDetailMapper.updateBatch(orderSubsidyDetailDOList, orderSubsidyDetailDOList.size());
        List<OrderSubsidyDetailDO> orderSubsidyDetailDOS = querySubsidyDetailInfo(batchNo);
        List<OrderSubsidyDetailDO> successCollect = orderSubsidyDetailDOS.stream()
                .filter(orderSubsidyDetailDO -> PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.SUCCESS.getCode().equals(orderSubsidyDetailDO.getSubsidyStatus())).collect(Collectors.toList());
        // List<OrderFundDetailDO> failList = orderFundDetailList.stream()
        // .filter(orderFundDetailDO ->
        // PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.FAIL.getCode().equals(orderFundDetailDO.getFundStatus())).collect(Collectors.toList());
        List<OrderSubsidyDetailDO> collect = orderSubsidyDetailDOS.stream()
                .filter(orderSubsidyDetailDO -> (!PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.FAIL.getCode().equals(orderSubsidyDetailDO.getSubsidyStatus())
                        && !PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.SUCCESS.getCode().equals(orderSubsidyDetailDO.getSubsidyStatus())))
                .collect(Collectors.toList());

        OrderSubsidyDto orderSubsidyDto = new OrderSubsidyDto();
        orderSubsidyDto.setOrderSubsidyDetailList(orderSubsidyDetailDOS);
        if (CollectionUtils.isEmpty(collect)) {
            OrderSubsidyDO orderSubsidyDO = queryOrderSubsidyInfo(batchNo, null);
            OrderSubsidyDO updateOrderSubsidyDO = new OrderSubsidyDO();
            updateOrderSubsidyDO.setId(orderSubsidyDO.getId());
            if (CollectionUtils.isEmpty(successCollect)) {
                updateOrderSubsidyDO.setSubsidyStatus(PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.FAIL.getCode());
                orderSubsidyDO.setSubsidyStatus(PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.FAIL.getCode());
            }
            else {
                updateOrderSubsidyDO.setSubsidyStatus(PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.SUCCESS.getCode());
                orderSubsidyDO.setSubsidyStatus(PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS.SUCCESS.getCode());
            }
            orderSubsidyMapper.updateById(updateOrderSubsidyDO);
            orderSubsidyDto.setOrderSubsidyDO(orderSubsidyDO);
        }
        return orderSubsidyDto;
    }

    @Override
    public OrderSubsidyDto querySubsidyDto(String batchNo) {
        LambdaQueryWrapperX<OrderSubsidyDetailDO> lambdaQueryWrapper = new LambdaQueryWrapperX<>();
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDetailDO::getBatchNo, batchNo);
        OrderSubsidyDto orderSubsidyDto = new OrderSubsidyDto();
        orderSubsidyDto.setOrderSubsidyDO(orderSubsidyMapper.selectOne(OrderSubsidyDO::getBatchNo, batchNo));
        orderSubsidyDto.setOrderSubsidyDetailList(orderSubsidyDetailMapper.selectList(lambdaQueryWrapper));
        return orderSubsidyDto;
    }

    @Override
    public OrderSubsidyDto querySubsidyDtoByPayOrderNo(String payOrderNo) {
        LambdaQueryWrapperX<OrderSubsidyDO> lambdaQueryWrapper = new LambdaQueryWrapperX<>();
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getPayOrderNo, payOrderNo);
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getPayType, CommonEnum.YES_NO_TYPE.NO.getCode());
        OrderSubsidyDto orderSubsidyDto = new OrderSubsidyDto();
        List<OrderSubsidyDO> orderSubsidyList = orderSubsidyMapper.selectList(lambdaQueryWrapper);
        if (CollUtil.isNotEmpty(orderSubsidyList)) {
            return null;
        }
        OrderSubsidyDO orderSubsidyDO = orderSubsidyList.get(0);
        orderSubsidyDto.setOrderSubsidyDO(orderSubsidyDO);
        PayOrderSubsidyQueryDto payOrderSubsidyQueryDto = new PayOrderSubsidyQueryDto();
        payOrderSubsidyQueryDto.setBatchNo(orderSubsidyDO.getBatchNo());
        orderSubsidyDto.setOrderSubsidyDetailList(orderSubsidyDetailMapper.selectList(buildDetailQueryWrapper(payOrderSubsidyQueryDto)));
        return orderSubsidyDto;
    }
    @Override
    public List<OrderSubsidyDetailDO> querySubsidyDetailInfo(String batchNo) {
        LambdaQueryWrapperX<OrderSubsidyDetailDO> lambdaQueryWrapper = new LambdaQueryWrapperX<>();
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDetailDO::getBatchNo, batchNo);
        return orderSubsidyDetailMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    public List<OrderSubsidyDO> querySubsidyList(PayOrderSubsidyQueryDto payOrderSubsidyQueryDto) {
        return orderSubsidyMapper.selectList(buildQueryWrapper(payOrderSubsidyQueryDto));
    }

    @Override
    public void updateSubsidyStatus(Long id, PayOrderEnums.PAY_ORDER_SUBSIDY_STATUS payOrderSubsidyStatus) {
        OrderSubsidyDO orderSubsidyDO = new OrderSubsidyDO();
        orderSubsidyDO.setId(id);
        orderSubsidyDO.setSubsidyStatus(payOrderSubsidyStatus.getCode());
        orderSubsidyMapper.updateById(orderSubsidyDO);
    }


    @Override
    public void updateSubsidyDetails(List<OrderSubsidyDetailDO> orderSubsidyDetailDOS) {
        orderSubsidyDetailMapper.updateBatch(orderSubsidyDetailDOS,orderSubsidyDetailDOS.size());
    }

    @Override
    public PageResult<OrderSubsidyDO> queryPage(PayOrderSubsidyQueryDto orderSubsidyQueryDto) {
        return orderSubsidyMapper.selectPage(orderSubsidyQueryDto, buildQueryWrapper(orderSubsidyQueryDto));
    }

    LambdaQueryWrapperX<OrderSubsidyDO> buildQueryWrapper(PayOrderSubsidyQueryDto payOrderSubsidyQueryDto) {
        filterSn(payOrderSubsidyQueryDto);
        LambdaQueryWrapperX<OrderSubsidyDO> lambdaQueryWrapper = new LambdaQueryWrapperX<>();
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getBatchNo, payOrderSubsidyQueryDto.getBatchNo());
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getPayOrderNo, payOrderSubsidyQueryDto.getPayOrderNo());
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getSubsidyStatus, payOrderSubsidyQueryDto.getSubsidyProcessType());
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getSubsidyProcessType, payOrderSubsidyQueryDto.getSystemProcessType());
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getSystemProcessType, payOrderSubsidyQueryDto.getSystemProcessType());
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getMchOrderNo, payOrderSubsidyQueryDto.getMchOrderNo());
        // lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getRefundOrderNo, payOrderSubsidyQueryDto.getMchRefundOrderNo());
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getPayType, payOrderSubsidyQueryDto.getPayType());
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDO::getSn,payOrderSubsidyQueryDto.getSn());
        return lambdaQueryWrapper;
    }

    LambdaQueryWrapperX<OrderSubsidyDetailDO> buildDetailQueryWrapper(PayOrderSubsidyQueryDto payOrderSubsidyQueryDto) {
        LambdaQueryWrapperX<OrderSubsidyDetailDO> lambdaQueryWrapper = new LambdaQueryWrapperX<>();
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDetailDO::getBatchNo, payOrderSubsidyQueryDto.getBatchNo());
        lambdaQueryWrapper.inIfPresent(OrderSubsidyDetailDO::getBatchNo, payOrderSubsidyQueryDto.getBatchNos());
        lambdaQueryWrapper.eqIfPresent(OrderSubsidyDetailDO::getSubsidyStatus, payOrderSubsidyQueryDto.getSubsidyStatus());
        return lambdaQueryWrapper;
    }
}
